<?php

/**
 * Author：晴玖天
 * Creation：2020/4/22 13:32
 * Filename：Order.php
 * 订单操作类
 */

namespace lib\supply;


use CookieCache;
use extend\Buy;
use extend\SMS;
use extend\UserConf;
use lib\Hook\Hook;
use Medoo\DB\SQL;

class Order
{

    /**
     * @param $PayOrder //支付订单号
     * @param $Pay //支付回调信息,支付订单数据
     * @param $Type =2则返回show_msg信息
     */
    public static function SubmitPay($Order, $Pay)
    {
        global $date;
        $DB = SQL::DB();
        $Goods = $DB->get('goods', '*', ['gid' => (int)$Order['gid']]);
        if (!$Goods) return ['code' => -1, 'msg' => '此订单商品不存在,无法提交至服务器,请联系管理员处理！'];
        $OrderData = Buy::OrderGet($Goods['gid'], $Order['order']);
        if ($OrderData['code'] != 1) {
            return $OrderData;
        }
        $OrderData = $OrderData['data'];
        $Data = Buy::CreateOrder($OrderData['gid'], $OrderData['order'], $Order['type'], $Order['trade_no']);
        if ($Data['code'] == 1) {
            $OrderID = $Data['data'];
            //开始发货
            Buy::Delivery($OrderID['id']);
            //调整充值订单状态
            $Res = $DB->update('pay', [
                'state' => 1,
                'trade_no' => $Pay['trade_no'],
                'endtime' => $date,
                'oid' => $OrderID['id'],
            ], [
                'id' => $Order['id']
            ]);
            if ($Res) {
                if ($OrderData['uid'] >= 1) {
                    userlog('在线购买', '用户[' . $OrderData['uid'] . ']在' . $date . '在线支付了' . $Order['money'] . '元购买了商品[' . $OrderData['name'] . ']！', $OrderData['uid'], $Order['money']);
                }
                Hook::execute('PaySuccess', [
                    'PayOrder' => $DB->get('pay', '*', ['id' => (int)$Order['id']]),
                    'type' => 1,
                ]);
                return [
                    'code' => 1,
                    'msg' => '商品[' . $OrderData['name'] . ']购买成功!',
                    'id' => $OrderID['id']
                ];
            }
        } else {
            return [
                'code' => -1,
                'msg' => $Data['msg'] ?? '订单创建失败，请联系客服处理！',
            ];
        }
    }

    /**
     * @param $DataBuy //下单信息
     * @param $User //用户信息
     * @param $Type //如果=1，则正常付款，如果=2，则无需付款
     * 下单信息处理模块
     * 下单验证，在线付款链接生成，
     */
    public static function Creation($DataBuy, $User, $Type = 1)
    {
        if (!$DataBuy['CouponId']) {
            $DataBuy['CouponId'] = -1;
        }
        $Verify = Buy::Verify($DataBuy['gid'], $DataBuy['num'], $DataBuy['data'], $User, $DataBuy);
        if ($Verify['code'] != 1) {
            dies(-1, $Verify['msg']);
        }
        //开始计算商品价格
        $Goods = $Verify['data'];
        $Verify = Buy::Price($Goods, $DataBuy);
        if ($Verify['code'] != 1) {
            dies(-1, $Verify['msg']);
        }
        $Goods = $Verify['data'];
        //开始创建待付款商品订单，如果创建成功就开始付款
        $Order = Buy::Create($Goods, $DataBuy);
        if ($Order['code'] != 1) {
            dies(-1, $Order['msg']);
        }
        $Order = $Order['data'];
        //开始执行订单付款操作，如果付款成功就返回成功
        $PayRes = Buy::Pay($Order['order'], $Order['gid'], $Type);
        if ($PayRes['code'] != 1) {
            dies(-1, $PayRes['msg']);
        }
        //开始执行订单创建流程[数据库订单]
        $OrderNew = Buy::CreateOrder($Order['gid'], $Order['order'], $PayRes['payment']);
        if ($OrderNew['code'] != 1) {
            dies(-1, $OrderNew['msg']);
        }
        //订单发货
        return Buy::Delivery($OrderNew['data']['id']);
    }

    /**
     * @param array $Goods
     * @param $Num //购买份数
     * @param $Oid //订单ID
     * @param $INPUT //下单信息
     * @return bool
     * 减少商品库存
     */
    public static function ReduceStocks(array $Goods, $Num, $Oid, $INPUT)
    {
        if ((int)$Goods['deliver'] === 3) {
            return true;
        }

        $DB = SQL::DB();
        $GoodsShi = $DB->query('select specification_sku,quota from sky_goods where  gid=:gid  for update;', [
            ':gid' => $Goods['gid'],
        ])->fetchAll()[0];

        if ((int)$Goods['specification'] === 2) {
            //如果已经开启商品规格配置！,并且商品库存里面的内容不是默认，那么只减少规格内的商品库存！
            $SKU = json_decode($GoodsShi['specification_sku'], TRUE);
            $SPU = json_decode($Goods['specification_spu'], TRUE);
            $KeyName = [];
            $SpuIn = 0; //初始化
            $InputArr = [];
            foreach ($SPU as $val) {
                $input = $INPUT[$SpuIn];
                foreach ($INPUT as $v) {
                    if (in_array($v, $val)) {
                        $input = $v;
                    }
                }
                $InputArr[$SpuIn] = $input;
                ++$SpuIn;
            }
            foreach ($InputArr as $v) {
                $KeyName[] = $v;
            }

            $NameKey = implode('`', $KeyName);
            if (empty($NameKey)) {
                $SQL = [
                    'quota[-]' => $Num,
                ];
            } else {
                if ((int)$SKU[$NameKey]['quota'] >= 1) {
                    $SKU[$NameKey]['quota'] -= $Num;
                    if ($SKU[$NameKey]['quota'] < 0) {
                        $SKU[$NameKey]['quota'] = 0;
                    }
                    $SQL = [
                        'specification_sku' => json_encode($SKU),
                    ];
                } else {
                    $SQL = [
                        'quota[-]' => $Num,
                    ];
                }
            }
        } else {
            $SQL = [
                'quota[-]' => $Num,
            ];
        }

        $Res = $DB->update('goods', $SQL, [
            'gid' => $Goods['gid'],
        ]);

        $DB->query('commit;'); //释放锁

        if ($Res) {
            return true;
        }
        return false;
    }


    /**
     * @param $Goods
     * @return void
     * 下拉选择参数值匹配
     * 这里新增了两个参数，如果inputType为真，则需要判断下拉选择框的参数，参数在：inputList里面
     */
    public static function GoodsInputs(&$Goods)
    {
        $InputList = [];
        $Goods['inputType'] = false;
        foreach (explode('|', $Goods['input']) as $value) {
            if (strstr($value, '{') && strstr($value, '}')) {
                $Ex = explode('{', $value);
                $Ex2 = explode(',', explode('}', $Ex[1])[0]);
                foreach ($Ex2 as $k => $v) {
                    if (strstr($v, ':') !== false) {
                        $ex = explode(':', $v);
                        $Ex2[$k] = $ex;
                        $Goods['inputType'] = true;
                    } else {
                        $Ex2[$k] = $v;
                    }
                }
                $InputList[] = $Ex2;
            } else {
                $InputList[] = $value;
            }
        }
        $Goods['inputList'] = $InputList;
    }

    /**
     * @param $Order
     * @param $Goods
     * @return void
     * 下单信息参数匹配【下拉选择项ID】
     */
    public static function OrderInputs(&$Order, $Goods)
    {
        if ($Goods['inputType']) {
            $Count = 0;
            if ((int)$Goods['specification'] === 2) {
                $Count = count(json_decode($Goods['specification_spu'], true));
            }
            $InputData = json_decode($Order['input'], true);
            foreach ($Goods['inputList'] as $k => $v) {
                if (is_array($v)) {
                    foreach ($v as $vv) {
                        if ($vv[0] == $InputData[$k + $Count]) {
                            $InputData[$k + $Count] = $vv[1];
                        }
                    }
                }
            }
            $Order['input'] = json_encode($InputData, JSON_UNESCAPED_UNICODE);
        }
    }

    /**
     * @param $OrData //商品订单号！
     * @param $Goods //下单商品信息
     * @param $Type 1正常，2补单
     * @param $QueueType //是否为队列执行
     * 订单创建后的执行操作
     */
    public static function OrderSubmit($OrData, $Goods, $Type = 1, $QueueType = false)
    {
        self::GoodsInputs($Goods);
        global $conf;
        if (!$QueueType && $Type === 1 && $conf['DelayedDocking'] == 1) {
            //写入延迟队列，使用文件缓存，文件地址：
            mkdirs(SYSTEM_ROOT . 'extend/log/Order/Delayed/');
            $File = SYSTEM_ROOT . 'extend/log/Order/Delayed/' . md5($OrData['order']) . '.json';
            //开始创建缓存
            $Data = [
                'OrData' => $OrData,
                'Goods' => $Goods,
                'date' => date('Y-m-d H:i:s')
            ];
            file_put_contents($File, json_encode($Data, JSON_UNESCAPED_UNICODE));
            return $OrData['id'];
        }
        switch ((int)$Goods['deliver']) {
            case 1:
                /**
                 * 自营商品
                 */
                Hook::execute('SalfordDelivery', $OrData);
                return self::Autotrophy($OrData, $Type);
            case 2:
                /**
                 * API对接商品
                 */
                $Data = Api::Submit($OrData, $Goods);
                if (!$Data) {
                    return $OrData['id'];
                }
                return self::OrderSet($OrData['id'], ($Data['code'] >= 0 ? $conf['SubmitStateSuccess'] : $conf['SubmitState']), $Data['msg'], $Data['order'], $Data['money'], $Type, $Data['docking']);
            case 3:
                /**
                 * 发卡商品
                 */
                $Data = faka::Submit($OrData, $Goods);
                if (!$Data) {
                    return $OrData['id'];
                }
                return self::OrderSet($OrData['id'], ($Data['code'] >= 0 ? $conf['SubmitStateSuccess'] : $conf['SubmitState']), $Data['msg'], $Data['order'], 0, $Type);
            case 4:
                /**
                 * 显示隐藏内容
                 */
                Hook::execute('HiddenContentShipment', $OrData);
                return self::OrderSet($OrData['id'], $conf['SubmitStateSuccess'], '商品购买成功，请在订单内查看详情！', '-1', '0', $Type);
            case 5:
                /**
                 * 主机空间发货
                 */
                $Data = self::HostCreation($OrData, $Goods);
                if (!$Data) {
                    return $OrData['id'];
                }
                return self::OrderSet($OrData['id'], $Data['code'], $Data['msg'], -1, 0, $Type, $Data['docking']);
            default:
                /**
                 * 对接货源
                 */
                $DB = SQL::DB();
                $TypeSupply = $DB->get('shequ', '*', [
                    'id' => (int)$Goods['sqid'],
                ]);
                if (!$TypeSupply) {
                    return self::OrderSet($OrData['id'], $conf['SubmitState'], '请检查编号[' . $Goods['sqid'] . ']的货源是否存在，可以尝试重新配置商品对接解决此问题！', -1, 0, $Type);
                }

                if ((string)$TypeSupply['class_name'] === '-1' || $TypeSupply['class_name'] === '') {
                    $TypeSupply['class_name'] = StringCargo::DataConversion($TypeSupply['type']);
                }
                if ((string)$TypeSupply['class_name'] === '0') {
                    $TypeSupply['class_name'] = 'jiuwu';
                }

                $TypeSupply['url'] = StringCargo::UrlVerify($TypeSupply['url']);

                $Source = StringCargo::Docking($TypeSupply['class_name']);
                if (empty($Source)) {
                    return self::OrderSet($OrData['id'], $conf['SubmitState'], '可对接货源类型【' . $TypeSupply['class_name'] . '】不存在！,可能此对接方式已被移除！', -1, 0, $Type);
                }
                $Order = $DB->get('order', '*', ['id' => (int)$OrData['id']]);
                //跳过同系统，同系统会自己判断是否需要调整下单提交参数
                if ($TypeSupply['class_name'] !== 'xiaochu') {
                    self::OrderInputs($Order, $Goods);
                }
                if ((int)$Order['docking'] === 4) {
                    dies(-1, '已经提交过了,无法重复提交对接！');
                }

                $Data = StringCargo::Distribute([
                    'Goods' => $Goods,
                    'Order' => $Order,
                    'Supply' => $TypeSupply,
                    'Source' => $TypeSupply['class_name'], //对接数据类型
                    'controller' => 'Submit', //载入提交订单控制器！
                ]);

                /**
                 * 返回内容如下：
                 * 1、订单处理说明(msg)
                 * 2、对接订单状态(docking) 1,对接成功,2,对接失败(会因为余额不足或其他而出现),3待提交对接(对接错误，可能是配置信息有误！),4无需对接,-1,其他状态
                 * 3、本地订单状态(code) 本地订单处理状态
                 * 3、对接余额（可有可无）
                 * 4、远程订单号（必须有）
                 * 如果有卡密对接信息，则在控制器内写入到本地卡密内！
                 */

                if (!$Data || $Data === -1) {
                    return $OrData['id'];
                }
                //对接失败钩子
                if ($Data['docking'] == 2) {
                    Hook::execute('OrderDockingFailure', [
                        'order' => $OrData['order'],
                        'error' => $Data['msg'],
                    ]);
                }

                return self::OrderSet($OrData['id'], $Data['code'], $Data['msg'], $Data['order'], $Data['money'], $Type, $Data['docking']);
        }
    }

    /**
     * @param $OrData
     * @param $Goods
     * 主机空间发货
     * 注：此商品无法使用积分兑换(影响续费价格配置!)
     * @return array
     */
    public static function HostCreation($OrData, $Goods)
    {
        global $conf, $date;
        $GoodsData = json_decode($Goods['extend'], true); //对接数据
        if (empty($GoodsData['id'])) {
            return [
                'code' => $conf['SubmitState'],
                'docking' => 2,
                'msg' => '对接配置有误，请确保商品配置内的节点配置正确！',
                'money' => 0,
                'order' => 0,
            ];
        }

        $DB = SQL::DB();

        $Order = $DB->get('order', '*', ['id' => (int)$OrData['id']]);
        Order::OrderInputs($Order, $Goods);
        /**
         * 获取到期时间
         * 计算公式：商品发货数量 * 商品份数 * 30天
         */
        $month = $Order['num'] * $Goods['quantity'];
        $EndDate = date('Y-m-d H:i:s', strtotime(' + ' . ($month * 30) . ' day'));
        /**
         * 获取主机每月续期价格
         * 计算公式：订单手机 / (发货数量 * 商品份数)(1=30天)
         */
        $Price = (float)$Order['price'] / $month;

        $identification = md5(random_int(99999, 9999999) . '晴玖天商城系统' . time());

        $InputData = json_decode($Order['input'], TRUE);

        $Confs = [
            'concurrencyall' => (int)$InputData[0],
            'concurrencyip' => ceil($InputData[0] / 10),
            'traffic' => (int)str_replace('KB', '', $InputData[1]),
            'filesize' => (int)str_replace('MB', '', $InputData[2]),
            'maxdomain' => (int)str_replace('个', '', $InputData[3]),
        ];

        foreach ($Confs as $val) {
            if (empty($val)) {
                return [
                    'code' => $conf['SubmitState'],
                    'docking' => 2,
                    'msg' => '主机发货参数规格配置有误，请按照后台提示进行添加！',
                    'money' => 0,
                    'order' => 0,
                ];
            }
        }

        $SQL = [
            'oid' => $Order['id'],
            'identification' => $identification,
            'uid' => ($Order['uid'] <= 0 ? -1 : (int)$Order['uid']),
            'RenewPrice' => $Price,
            'server' => $GoodsData['id'],
            'sql_user' => '待生成',
            'sql_name' => '待生成',
            'sql_pass' => '待生成',
            'maxdomain' => $Confs['maxdomain'],
            'concurrencyall' => $Confs['concurrencyall'],
            'concurrencyip' => $Confs['concurrencyip'],
            'traffic' => $Confs['traffic'],
            'filesize' => $Confs['filesize'],
            'username' => $InputData[4],
            'password' => (empty($InputData[5]) ? '' : md5($InputData[5])),
            'endtime' => $EndDate,
            'addtime' => $date,
        ];


        if (!empty($Data['username'])) {
            $Vs1 = $DB->get('mainframe', ['id'], [
                'username' => (string)$Data['username'],
            ]);

            if ($Vs1) {
                return [
                    'code' => $conf['SubmitState'],
                    'docking' => 2,
                    'msg' => '此用户名已被其他主机占用！',
                    'money' => 0,
                    'order' => 0,
                ];
            }
        }

        $Vs = $DB->get('server', ['id', 'HostSpace'], [
            'id' => (int)$GoodsData['id'],
        ]);

        if (!$Vs) {
            return [
                'code' => $conf['SubmitState'],
                'docking' => 2,
                'msg' => '服务器节点不存在！',
                'money' => 0,
                'order' => 0,
            ];
        }

        $SQL['sizespace'] = $Vs['HostSpace'];

        $Res = $DB->insert('mainframe', $SQL);

        if ($Res) {
            $ID = $DB->id();
            if ($SQL['uid'] > 0) {
                userlog('主机创建', '主机空间发货成功，主机ID为：' . $ID, $SQL['uid']);
            }
            Hook::execute('DeliveryPagodaMainframe', [
                'order' => $OrData['order'],
                'id' => $ID,
                'uid' => $SQL['uid'],
            ]);
            return [
                'code' => $conf['SubmitStateSuccess'],
                'docking' => 1,
                'msg' => '主机创建成功，请前往主机管理列表查看，注：主机需要手动激活才可使用！',
                'money' => 0,
                'order' => 0,
            ];
        }

        return [
            'code' => $conf['SubmitState'],
            'docking' => 2,
            'msg' => '创建失败！，请重新尝试！',
            'money' => 0,
            'order' => 0,
        ];
    }

    /**
     * @param $OrData 订单ID+订单号
     * @param $Goods 商品信息
     * 自营商品提交,自营商品需扩展api控制订单
     */
    public static function Autotrophy($OrData, $Type)
    {
        global $conf;
        return self::OrderSet($OrData['id'], $conf['SubmitState'], '请联系客服查询具体进度!', '-1', '0', $Type);
    }

    /**
     * @param $state //订单状态
     * @param $return //对接返回信息
     * @param int $order_id 货源订单号
     * @param int $user_rmb 货源余额
     * @param int $Type 1订单创建后操作，2补单
     * 修改订单状态！写入社区订单号
     */
    public static function OrderSet($id, $state, $return, $order_id = -1, $user_rmb = 0, $Type = 1, $docking = 4)
    {
        global $conf;
        $DB = SQL::DB();
        $Res = $DB->update('order', [
            'state' => $state,
            'return' => $return,
            'order_id' => $order_id,
            'user_rmb' => $user_rmb,
            'docking' => $docking,
        ], ['id' => $id]);
        if ($Res && $Type === 1) {
            $Order = $DB->get('order', [
                '[>]goods' => ['gid' => 'gid'],
            ], [
                'order.gid',
                'order.uid',
                'order.price',
                'order.num',
                'order.input',
                'goods.name',
                'order.payment',
                'order.order',
                'order.trade_no',
                'order.muid',
            ], ['id' => (int)$id]);
            if ($Order) {
                $OrderGet = $DB->get('order', '*', ['id' => (int)$id]);
                $OrderGet['name'] = $Order['name'];
                Hook::execute('OrderFinish', $OrderGet);
                if ($Order['uid'] >= 1 && $conf['sms_switch_order'] == 1) {
                    SMS::OrderTips($Order['uid'], $Order['order']);
                }
                SMS::OrderEmailTips($Order['order'], $Order['name']);
                UserConf::PushMoney($Order['muid'], $Order['trade_no'], $Order['uid'], $Order['order'], $Order['gid'], (float)$Order['price'], ($Order['payment'] == '积分兑换' ? 2 : 1), $Order['num'], json_decode($Order['input'], TRUE));
            } else {
                dier($DB->error());
            }
        }
        return $id;
    }

    /**
     * @param $oid
     * @param $order
     * @param $Uid
     * @param $data
     * 修改下单信息
     */
    public static function OrderModification($oid, $OrderNum, $Uid, $data)
    {
        global $conf;
        if ((int)$conf['OrderModification'] !== 1) {
            dies(-1, '当前站点未开启下单信息自助修改！');
        }
        $DB = SQL::DB();
        if (!$Uid) {
            $SQL = [
                'id' => (int)$oid,
                'uid' => -1,
                'order' => (string)$OrderNum,
            ];
        } else {
            $SQL = [
                'id' => (int)$oid,
                'uid' => [(int)$Uid, -1],
                'order' => (string)$OrderNum,
            ];
        }
        $Order = $DB->get('order', '*', $SQL);
        if (!$Order) {
            dies(-1, '订单不存在，无法修改！');
        }
        if ((int)$Order['docking'] === 1) {
            dies(-1, '此商品已经提交至货源站，无法进行修改！');
        }
        $Goods = $DB->get('goods', '*', [
            'gid' => (int)$Order['gid'],
        ]);
        if (!$Goods) {
            dies(-1, '此商品已经下架，无法修改！');
        }
        if ((int)$Goods['specification'] === 2 && (int)$Goods['specification_type'] === 1) {
            dies(-1, '自选规格类商品无法修改！');
        }
        if ((int)$Goods['deliver'] === 5) {
            dies(-1, '主机类商品无法修改下单信息！');
        }
        if ($Order['state'] != 2 && $Order['state'] != 3) {
            dies(-1, '此订单不满足修改条件，仅能修改待处理和异常订单的下单信息！');
        }
        $Input = json_decode($Order['input'], true);
        if (count($Input) !== count($data)) {
            dies(-1, '填写的参数异常！');
        }
        $Res = $DB->update('order', [
            'input' => json_encode($data, JSON_UNESCAPED_UNICODE),
        ], [
            'id' => $Order['id'],
        ]);
        if ($Res) {
            userlog('订单修改', (!$Uid ? '游客' : '用户:' . $Uid) . '修改了订单[ ' . $oid . ' ]的下单信息，新：' . json_encode($data, JSON_UNESCAPED_UNICODE) . '，旧：' . $Order['input'], (!$Uid ? 0 : $Uid));
            dies(1, '修改成功！');
        } else {
            dies(-1, '修改失败！');
        }
    }

    /**
     * 订单状态监控
     */
    public static function OrderStatusMonitoring($Num = 10)
    {
        $DB = SQL::DB();

        $Array = file_get_contents(ROOT . 'assets/log/OrderList.log');
        $Array = explode('|', $Array);
        $Time_3s = date('Y-m-d H:i:s', strtotime('-3 day'));
        $Count = $DB->count('order', [
            'state[!]' => [5, 1], //不监控已退款和已完成订单
            'order_id[!]' => [-1, ''],
            'addtitm[>]' => $Time_3s,
        ]);

        if ($Count === 0) {
            @unlink(ROOT . 'assets/log/OrderList.log');
            dies(-1, '无可监控订单,即将开始下一轮监控！', 2);
        }

        $OrderList = $DB->select('order', '*', [
            'state[!]' => [5, 1],
            'order_id[!]' => [-1, ''],
            'addtitm[>]' => $Time_3s,
            'ORDER' => 'id',
            'id[!]' => $Array,
            'LIMIT' => $Num,
        ]);
        if (!$OrderList || count($OrderList) == 0) {
            @unlink(ROOT . 'assets/log/OrderList.log');
            dies(-2, '无可监控订单,即将开始下一轮监控！', 2);
        }
        $List = [];
        foreach ($OrderList as $Order) {
            $Goods = $DB->get('goods', '*', [
                'gid' => (int)$Order['gid'],
            ]);

            if (!$Goods) {
                file_put_contents(ROOT . 'assets/log/OrderList.log', $Order['id'] . '|', FILE_APPEND);
                $List[] = "订单{$Order['id']}无需监控，对应商品已经删除！";
                continue;
            }

            $TypeSupply = $DB->get('shequ', '*', [
                'id' => (int)$Goods['sqid'],
            ]);
            if (!$TypeSupply) {
                file_put_contents(ROOT . 'assets/log/OrderList.log', $Order['id'] . '|', FILE_APPEND);
                $List[] = "订单{$Order['id']}对接货源不存在，无法完成订单监控！";
                continue;
            }

            if ((string)$TypeSupply['class_name'] === '-1' || $TypeSupply['class_name'] === '') {
                $TypeSupply['class_name'] = StringCargo::DataConversion($TypeSupply['type']);
            }
            if ((string)$TypeSupply['class_name'] === '0') {
                $TypeSupply['class_name'] = 'jiuwu';
            }

            $ApiData = StringCargo::Distribute([
                'Order' => $Order,
                'Supply' => $TypeSupply,
                'Source' => $TypeSupply['class_name'],
                'controller' => 'Query',
            ]);
            if (count($ApiData) === 0 || empty($ApiData['ApiStateNum'])) {
                file_put_contents(ROOT . 'assets/log/OrderList.log', $Order['id'] . '|', FILE_APPEND);
                $List[] = "订单{$Order['id']}无法获取远程订单数据，无法完成更新！";
                continue;
            }

            if ($ApiData['ApiStateNum'] == 5) {
                file_put_contents(ROOT . 'assets/log/OrderList.log', $Order['id'] . '|', FILE_APPEND);
                $List[] = "订单{$Order['id']}已退款,已单独标出,请前往商品列表处理！";
                //已退款订单，仅标出【修改订单备注】
                $DB->update('order', [
                    'return' => "此对接订单已退单,请手动退单!", //如果对接返回信息=订单编号，就表示此订单已经退单
                ], [
                    'id' => $Order['id'],
                ]);
                continue;
            }

            $Res = $DB->update('order', [
                'state' => $ApiData['ApiStateNum'],
            ], [
                'id' => $Order['id'],
            ]);
            file_put_contents(ROOT . 'assets/log/OrderList.log', $Order['id'] . '|', FILE_APPEND);
            if ($Res) {
                $List[] = "订单{$Order['id']}数据同步成功，此订单状态为：【" . $ApiData['ApiState'] . "】";
            } else {
                $List[] = "订单{$Order['id']}数据同步失败，无法更新数据库信息，此订单状态为：【" . $ApiData['ApiState'] . "】";
            }
        }
        dier([
            'code' => 1,
            'msg' => '订单同步结果如下',
            'data' => $List
        ]);
    }

    /**
     * @param $ID //订单ID
     * @param false $Uid 用户ID,无则为游客
     * @param int $Type 1普通用户查询，2主站后台查询
     * @param false $OrderNum 订单号，游客查询时需要！
     * @return array
     * 查询订单进度！
     */
    public static function Query($ID, $Uid = false, $Type = 1, $OrderNum = false)
    {
        global $conf;
        $DB = SQL::DB();
        if ($Type === 2) {
            //主站后台
            $Order = $DB->get('order', '*', [
                'id' => (int)$ID,
            ]);
        } else if ($Type === 1) {
            //前台用户查单
            if (empty($OrderNum)) {
                dies(-1, '订单号不能为空！');
            }
            if (!$Uid) {
                //游客
                $SQL = [
                    'id' => (int)$ID,
                    'uid' => -1,
                    'order' => (string)$OrderNum,
                ];
            } else {
                //指定用户
                $SQL = [
                    'id' => (int)$ID,
                    'uid' => [(int)$Uid, -1],
                    'order' => (string)$OrderNum,
                ];
            }
            $Order = $DB->get('order', '*', $SQL);
        } else if ($Type === 3) {
            //api对接查单
            $Order = $DB->get('order', '*', [
                'OR' => [
                    'order' => (string)$ID,
                    'id' => (int)$ID,
                ],
                'uid' => (int)$Uid,
                'LIMIT' => 1,
            ]);
        } else {
            dies(-1, '查单方式不存在！');
        }

        if (!$Order) {
            dies(-1, '订单不存在！');
        }

        $Data = [
            'id' => $Order['id'],
            'gid' => $Order['gid'],
            'order' => $Order['order'],
            'ip' => $Order['ip'],
            'price' => round((float)$Order['price'], 8), //购买金额
            'originalprice' => round((float)$Order['originalprice'], 8), //原价
            'coupon' => $Order['coupon'],
            'discounts' => ($Order['coupon'] == -1 ? -1 : round($Order['originalprice'] - ($Order['price']), 8)),
            'addtiem' => $Order['addtitm'],
            'finishtime' => $Order['finishtime'],
            'endtime' => $Order['finishtime'],
            'state' => self::OrderState((int)$Order['state']),
            'stateid' => (int)$Order['state'],
            'type' => $Order['payment'],
            'remark' => $Order['remark'],
            'num' => $Order['num'], //购买份数
            'take' => $Order['take'], //收货状态
            'logistics' => $Order['logistics'],
            'uid' => $Order['uid'],
        ];
        $Goods = $DB->get('goods', '*', [
            'gid' => (int)$Order['gid'],
        ]);

        if (!$Goods) {
            //商品丢失，简查询
            $Input = [];
            foreach (json_decode($Order['input'], true) as $key => $v) {
                $Input[] = '输入框' . ($key + 1) . '：' . $v;
            }
            $Data['input'] = $Input;
            $Data['name'] = '商品已删除';
            $Data['docs'] = '商品已丢失，无法查看商品说明';
            $Data['ApiSn'] = -1;
            $Data['quantity'] = 1;
            $Data['units'] = '个';
            $Data['Explain'] = -1;
        } else {
            //存在，复杂查询
            if ($Goods['deliver'] == -1 && $Order['order_id'] != -1 && $Order['order_id'] != '' && $Order['order_id'] != 1) {
                //对接查询
                $TypeSupply = $DB->get('shequ', '*', [
                    'id' => (int)$Goods['sqid'],
                ]);
                if ($TypeSupply) {
                    //根据可对接列表查询，便于后期扩展！
                    /**
                     * 'ApiType' => 订单查询状态,
                     * 'ApiNum' => 对接购买数量,
                     * 'ApiTime' => 订单创建时间,
                     * 'ApiInitial' => 初始数量,
                     * 'ApiPresent' => 现在完成数量,
                     * 'ApiState' => 现在订单状态(文字说明),
                     * 'ApiError' => 订单异常信息，或处理结果,
                     */
                    if ((string)$TypeSupply['class_name'] === '-1' || $TypeSupply['class_name'] === '') {
                        $TypeSupply['class_name'] = StringCargo::DataConversion($TypeSupply['type']);
                    }
                    if ((string)$TypeSupply['class_name'] === '0') {
                        $TypeSupply['class_name'] = 'jiuwu';
                    }
                    $ApiData = StringCargo::Distribute([
                        'Order' => $Order,
                        'Supply' => $TypeSupply,
                        'Source' => $TypeSupply['class_name'], //对接数据类型
                        'controller' => 'Query', //载入查询订单控制器！
                    ]);
                }

                if ($ApiData && $ApiData !== -1 && count($ApiData) >= 1) {
                    //返回数据正常的话，则合并
                    $Data = array_merge($Data, $ApiData);
                }
            } else {
                $ApiData = [];
            }

            $InputArr = json_decode($Order['input'], true);
            $i = 0;
            $GoodsInputArr = explode('|', $Goods['input']);

            if ($Goods['specification'] == 2) {
                $SpRule = RlueAnalysis($Goods, 3);
                if ($SpRule != -1) {
                    $GoodsInputArr = array_merge($SpRule['MasterRule'], $GoodsInputArr);
                }
            }

            $GoodsInput = [];
            foreach ($InputArr as $value) {
                if (empty($value)) {
                    continue;
                }
                if (empty($GoodsInputArr[$i])) $GoodsInputArr[$i] = '输入框' . ($i + 1);
                if (strstr($GoodsInputArr[$i], '{') && strstr($GoodsInputArr[$i], '}')) {
                    $GoodsInput[] = explode('{', $GoodsInputArr[$i])[0] . '：' . $value;
                } else {
                    $GoodsInput[] = TakeMultipleNames($GoodsInputArr[$i]) . '：' . $value;
                }
                ++$i;
            }

            $Data['input'] = $GoodsInput;
            $Data['name'] = $Goods['name'];
            $Data['docs'] = htmlspecialchars_decode($Goods['docs']);
            $Data['ApiSn'] = (count($ApiData) <= 2 ? -1 : 1);
            $Data['quantity'] = $Goods['quantity'];
            $Data['units'] = $Goods['units'];
            $Data['Explain'] = (empty($Goods['explain']) ? -1 : $Goods['explain']);
        }

        //V3.5+新增，需要同步对接文件才可生效，隐藏内容发货对接！
        $Explain = SYSTEM_ROOT . 'extend/log/Order/' . $Order['order'] . '_explain.log';
        if (file_exists($Explain)) {
            $Data['Explain'] = file_get_contents($Explain);
        }

        $CountHost = $DB->get('mainframe', ['id'], [
            'oid' => (int)$Order['id'],
        ]);
        if ($CountHost) {
            $Data['HostType'] = 1;
        } else {
            $Data['HostType'] = -1;
        }

        if ($Type === 2) {
            //主站可观测数据
            $Data['return'] = $Order['return'];
            $Data['trade_no'] = $Order['trade_no'];
            $Data['muid'] = $Order['muid'];
            $Data['docking'] = $Order['docking']; //对接状态
            $Data['order_id'] = $Order['order_id'];
            $Data['money'] = round($Order['money'], 8); //成本
            $Data['user_rmb'] = round($Order['user_rmb'], 8); //对接余额
        } else {
            //检查ApiError参数是否包含：管理员帮您在后台进行了退款操作
            if (strstr($Data['ApiError'], '管理员帮您在后台进行了退款操作')) {
                $Data['ApiError'] = '订单已退款';
            }
        }

        $GetToken = $DB->select('token', ['token'], ['order' => $Order['order']]);
        if (count($GetToken) >= 1) {
            $TokenArr = [];
            foreach ($GetToken as $value) {
                $TokenArr[] = $value['token'];
            }
        } else {
            $TokenArr = -1;
        }
        $Data['token_arr'] = $TokenArr;

        //载入应用钩子
        $Expansion = OrderDetailExtent($Data);
        if ($Expansion && count($Expansion) >= 1) {
            $Data['Expansion'] = $Expansion;
        } else {
            $Data['Expansion'] = [];
        }

        //载入订单缓存商品数据
        if (!empty($Order['name'])) {
            $Data['name'] = $Order['name'];
        }
        if (!empty($Order['quantity'])) {
            $Data['quantity'] = $Order['quantity'];
        }
        if (!empty($Order['units'])) {
            $Data['units'] = $Order['units'];
        }
        if (!empty($Order['docs'])) {
            $Data['docs'] = htmlspecialchars_decode($Order['docs']);
        }

        return [
            'code' => 1,
            'msg' => '订单查询成功',
            'data' => $Data,
            'OrderModification' => $conf['OrderModification']
        ];
    }

    /**
     * @param $Id // 类型参数
     * 返回状态
     */
    private static function OrderState($Id)
    {
        switch ($Id) {
            case 1:
                return '已完成';
            case 2:
                return '待处理';
            case 3:
                return '异常';
            case 4:
                return '正在处理';
            case 5:
                return '已退款';
            case 6:
                return '售后中';
            case 7:
                return '已评价';
            default:
                return '未知状态';
        }
    }

    /**
     * @param $ID //订单补单！
     * 目前只有补单功能独立于订单创建外,其他均要验证订单！
     */
    public static function Retry($ID)
    {
        global $conf;
        $DB = SQL::DB();
        $Order = $DB->get('order', '*', [
            'id' => (int)$ID,
        ]);
        if ((int)$Order['state'] === 1) {
            dies(-1, '已完成订单无法补单！');
        }
        $Data = [
            'id' => $ID,
            'order' => $Order['order'],
        ];
        $Goods = $DB->get('goods', '*', [
            'gid' => (int)$Order['gid'],
        ]);

        if (!$Goods) dies(-1, '商品不存在,无法补单！');

        $Sku = json_decode($Order['input'], TRUE);

        if ($Goods['specification'] == 2) {
            $SpRule = RlueAnalysis($Goods, 1);
            $SkuData = [
                'data' => $SpRule,
                'SPU' => json_decode($Goods['specification_spu'], TRUE),
            ];

            $KeyName = [];
            $SpuIn = 0; //初始化
            $InputArr = [];
            foreach ($SkuData['SPU'] as $val) {
                $input = $Sku[$SpuIn];
                foreach ($Sku as $v) {
                    if (in_array($v, $val)) {
                        $input = $v;
                    }
                }
                $InputArr[$SpuIn] = $input;
                ++$SpuIn;
            }
            foreach ($InputArr as $v) {
                $KeyName[] = $v;
            }
            $DataRule = $SkuData['data']['Parameter'][implode('`', $KeyName)];
            if (empty($DataRule)) {
                dies(-1, '商品规格选择错误,请选择正确的参数!');
            }
            $Goods = array_merge($Goods, $DataRule);
        }

        $Goods['price'] = $Order['price'];
        $Goods['points'] = $Order['price'];
        $Goods['num'] = $Order['num'];

        $Re = self::OrderSubmit($Data, $Goods, 2);
        CookieCache::del('OrderListCountAll');
        if (!$Re) dies(-1, '补单失败，无法获取返回数据！');
        $return = $Order['return'];
        $Order = $DB->get('order', ['return', 'state'], [
            'id' => (int)$ID,
        ]);
        if ($Order['return'] == $return && $Order['state'] != $conf['SubmitStateSuccess']) dies(-1, '补单失败:<br>' . $Order['return']);
        if ($Order['state'] != $conf['SubmitStateSuccess']) {
            dies(-1, '补单失败：' . $Order['return']);
        } else  dies(1, '补单成功：' . $Order['return']);
    }
}
